
#include "DX9_Module.hpp"

namespace VoodooShader
{
	namespace DirectX9
	{
		Adapter::Adapter(Core * core, IDirect3DDevice9 * device)
			: mCore(core), mDevice(device)
		{
			HRESULT hr = cgD3D9SetDevice(device);
			if ( !SUCCEEDED(hr) )
			{
				Throw("Voodoo DX9: Could not set Cg device.", core);
			}

			Core * core = VoodooShader::Core::GetSingletonPtr();
			if ( !core )
			{
				// Narrowly avoided segfault right here. Luckily caught before it ever ran.
				//core->GetLog()->Log("Voodoo DX9: Initializing core...\n");
				core = new VoodooShader::Core();
			}
			
			core->GetLog()->Log("Voodoo DX9: Starting adapter...\n");

			try
			{
				core->SetAdapter(reinterpret_cast<VoodooShader::Adapter*>(this));
				core->GetLog()->Log("Voodoo DX9: Core adapter set to this.\n");
			} catch ( VoodooShader::Exception & exc ) {
				core->GetLog()->Log("Voodoo DX9: Error setting adapter on core.\n");
				//exit(1);
			}

			cgD3D9EnableDebugTracing(CG_TRUE);

			this->mDevice->CreateVertexBuffer(4 * sizeof(FSVert), 0, D3DFVF_CUSTOMVERTEX,
				D3DPOOL_DEFAULT, &FSQuadVerts, NULL);

			FSVert g_Vertices[4];
			g_Vertices[0].x = g_Vertices[0].y = -1.0f;
			g_Vertices[2].x = g_Vertices[2].y = 0.5f;
			g_Vertices[1].x = g_Vertices[3].y = -1.0f;
			g_Vertices[3].x = g_Vertices[1].y = 0.5f;

			g_Vertices[0].tu = g_Vertices[1].tu = 0.0f;
			g_Vertices[0].tv = g_Vertices[3].tv = 0.0f;
			g_Vertices[2].tu = g_Vertices[3].tu = 1.0f;
			g_Vertices[2].tv = g_Vertices[1].tv = 1.0f;

			g_Vertices[0].color = g_Vertices[2].color = 0xF800F8FF;
			g_Vertices[1].color = g_Vertices[3].color = 0xFF8F008F;

			VOID * pVertices;
			FSQuadVerts->Lock(0, sizeof(g_Vertices), &pVertices, 0);
			memcpy(pVertices, g_Vertices, sizeof(g_Vertices));
			FSQuadVerts->Unlock();
		}

		void Adapter::Bind(Shader * shader)
		{
			//! @todo Bind the shader here, need to apply params and set up textures
			CGeffect effect = shader->GetEffect();
			CGtechnique tech = cgGetFirstTechnique(effect);
			CGpass pass = cgGetFirstPass(tech);

			while ( pass != NULL )
			{
				cgSetPassState(pass);
				this->DrawFSQuad();
				cgResetPassState(pass);
				pass = cgGetNextPass(pass);
			}
		}

		void Adapter::Unbind()
		{

		}

		void Adapter::DrawFSQuad()
		{
			IDirect3DVertexBuffer9 * sourceBuffer;
			UINT sourceOffset, sourceStride;
			DWORD sourceFVF;

			this->mDevice->GetStreamSource(0, &sourceBuffer, &sourceOffset, &sourceStride);
			this->mDevice->GetFVF(&sourceFVF);

			this->mDevice->SetStreamSource(0, FSQuadVerts, 0, sizeof(FSVert));
			this->mDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

			this->mDevice->BeginScene();
			this->mDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); 
			this->mDevice->EndScene();
			
			this->mDevice->SetStreamSource(0, sourceBuffer, sourceOffset, sourceStride);
			this->mDevice->SetFVF(sourceFVF);
		}
		void Adapter::Apply(Parameter * param)
		{
			switch ( param->mType )
			{
			case CG_FLOAT4:
			case CG_FLOAT3:
			case CG_FLOAT2:
			case CG_FLOAT1:
			case CG_FLOAT:
				cgD3D9SetUniform(param->mParam, param->mValueFloat);
				break;
			case CG_SAMPLER:
			case CG_SAMPLER1D:
			case CG_SAMPLER2D:
			case CG_SAMPLER3D:
			case CG_SAMPLERCUBE:
				//cgD3D9SetTextureParameter(param->mParam, param->mValueTexture->mTextureObject);
				break;
			}
		}

		void Adapter::HandleError(CGcontext context, CGerror error, void * core)
		{
			Core * actualCore = reinterpret_cast<Core*>(core);
			actualCore->GetLog()->Format->Record("Voodoo DX9: Cg error: %s\n").With(cgD3D9TranslateCGerror(error)).Done();
		}
	}
}